
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>限流工具RateLimiter - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>限流工具RateLimiter - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">在高并发系统中，为什么说限流是必选项而不是可选项？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">限流是必选项，因为它能：1. 防止系统因资源有限而过载；2. 避免上游服务的压力传导至下游导致连锁故障（雪崩）；3. 将突发流量分散处理，实现业务削峰平谷；4. 抵御DoS/DDoS等恶意攻击，保障系统稳定性。</div>
          </div>
          <div class="card-source">来源: 1.1 限流的必要性</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">Guava RateLimiter 提供了哪两种平滑限流的具体实现？它们的主要区别和适用场景是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Guava RateLimiter 提供了两种实现：1. SmoothBursty：允许一定程度的突发流量，适用于大部分通用场景。2. SmoothWarmingUp：带有预热期的平滑限流器，它使得系统在冷启动时速率较低，然后逐渐恢复到正常速率，适用于需要预热以避免系统瞬间过载的场景。</div>
          </div>
          <div class="card-source">来源: 1.4 RateLimiter的内部实现</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">Guava RateLimiter 是如何不实际维护一个令牌桶，却能实现令牌桶算法的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">RateLimiter 并不真正维护一个存放令牌的桶，而是通过计算下一次请求需要等待的时间来模拟令牌生成的过程。它记录了下一次可以免费获取令牌的时间点（nextFreeTicketMicros），当请求到来时，根据当前时间和这个时间点来计算出需要等待多久才能获取到所需令牌。</div>
          </div>
          <div class="card-source">来源: 1.4 RateLimiter的内部实现</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">在 SmoothRateLimiter 中，resync 方法的核心作用是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">resync 方法的核心作用是根据当前时间和上次请求的时间差，按需计算并“补充”这段时间内新生成的令牌。如果当前时间晚于 `nextFreeTicketMicros`，它会计算出新产生的令牌数并更新 `storedPermits`，然后将 `nextFreeTicketMicros` 更新为当前时间，从而同步令牌桶的状态。</div>
          </div>
          <div class="card-source">来源: 2.1 SmoothRateLimiter基类</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">SmoothBursty 和 SmoothWarmingUp 在消耗已存储令牌（storedPermits）时的核心行为差异是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">核心差异在于消耗已存储令牌是否需要等待。在 SmoothBursty 中，消耗已存储的令牌不需要任何额外等待时间，因此可以瞬间响应突发流量。而在 SmoothWarmingUp 中，消耗已存储的令牌需要计算一个等待时间，令牌数越多（越接近预热状态），获取单个令牌的等待时间就越长，从而实现速率的平滑提升。</div>
          </div>
          <div class="card-source">来源: 2.2 SmoothBursty实现分析 & 2.3 SmoothWarmingUp实现分析</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">RateLimiter 的令牌生成策略被称为“懒加载”，这种设计有什么优点？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">“懒加载”设计指的是 RateLimiter 并不会定时生成令牌，而是在请求到来时，根据上次请求的时间差，按需计算应该生成多少令牌。这种设计的优点是效率非常高，因为它避免了不必要的计时器调度和在系统空闲时的检查开销。</div>
          </div>
          <div class="card-source">来源: 3.2 令牌生成与分配策略</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">在API限流保护实践中，如何结合使用 RateLimiter 实现全局流量控制和用户级别隔离？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">可以创建一个全局的 RateLimiter 实例来限制系统的总体QPS，实现全局流量控制。同时，使用一个 `LoadingCache<String, RateLimiter>` 结构，为每个用户ID动态创建一个独立的 RateLimiter 实例，从而防止单个用户抢占所有资源，实现用户级别的隔离。</div>
          </div>
          <div class="card-source">来源: 4. API限流保护</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">与其他限流方案（如 Redis+Lua）相比，Guava RateLimiter 的主要缺点是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Guava RateLimiter 的主要缺点是它只支持单机限流，无法应用于分布式集群环境。对于分布式系统，需要考虑使用 Redis+Lua 或专业的限流组件（如Sentinel）等方案。</div>
          </div>
          <div class="card-source">来源: 5.2 与其他限流方案的对比</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">RateLimiter 是如何避免传统计数器算法中固定时间窗口带来的边界问题的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">RateLimiter 采用的是滑动窗口的思想，而不是固定的时间窗口。它通过计算从上一个请求到当前请求之间的时间差来动态生成令牌，使得限流更加平滑。这避免了在固定窗口边界处可能发生的流量突刺问题（例如，在一个窗口的末尾和下一个窗口的开头瞬间涌入大量请求）。</div>
          </div>
          <div class="card-source">来源: 3.1 时间窗口的设计</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
